﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;

namespace RDJTProtocolServer
{
    /**
     * Handler for Requests
     */
    class Rdjtp
    {
        public RdjtpRequest Request { get; private set; }
        public RdjtpResponse Response { get; private set; }

        // Accepted methods of the Server.
        private readonly List<string> _acceptedMethods = new List<string>(){ "create", "read", "update", "delete", "echo" };

        private string _message;

        public Rdjtp(string message)
        {
            _message = message;
        }

        public bool ValidateRequest()
        {
            var messages = new List<string>();

            try
            {
                var request = JsonConvert.DeserializeObject<RdjtpRequest>(_message);
                Request = request;
            }
            // WE ARE BEING CAUGHT DUE TO INT CONSTRAINT ON @Date. WE DO NOT KNOW, HOWEVER, FOR SURE THAT IT IS @Date THAT IS MESSED UP
            catch (JsonReaderException e)
            {
                Console.WriteLine(e);
                // THESE TWO LINES CREATES A HANDIER TYPE TO DO CHECKS ON. 
                var definition = new { Method = "", Path = "", Date = "", Body = "" };
                var caughtRequest = JsonConvert.DeserializeAnonymousType(_message, definition);

                int i = 0;
                // SINCE THE @Date MUST BE OF TYPE INTEGER, WE CAN NOTIFY CLIENT OF "ILLEGAL DATE" MESSAGE IF INPUT DATE CANNOT BE PARSED TO INTEGER
                if (!Int32.TryParse(caughtRequest.Date, out i))
                {
                    Response = new RdjtpResponse(RdjtpStatus.Error);
                    Response.Status = $"{Response.Status} illegal date";
                    return false;
                }
                Response = new RdjtpResponse(RdjtpStatus.Error);
                return false;
            }

            Response = new RdjtpResponse();

            if (!HeadersValid())
            {
                Response.Status = "4 ";

                if (Request.Method == null)
                {
                    messages.Add("missing method");
                }
                else
                {
                    // Checking for supported methods.
                    if (!_acceptedMethods.Contains(Response.Status))
                    {
                        messages.Add("illegal method");
                    }
                }
                if (Request.Path == null) messages.Add("missing resource");
                if (Request.Date == 0) messages.Add("missing date");
                if (Request.Date < 0 || Request.Date > DateTimeOffset.Now.ToUnixTimeSeconds())
                {
                    messages.Add("illegal date");
                }
            }

            Console.WriteLine("BODY:" + Request.Body);
            if (Request.Method == "create"
                || Request.Method == "update"
                || Request.Method == "echo")
            {
                if (Request.Body == null)
                {
                    messages.Add("missing body");
                }
                else if (Request.Body != null && Request.Method.Equals("echo"))
                {
                    Response.Status = RdjtpStatus.GetText(RdjtpStatus.Ok);
                    return true;
                }
                else {
                    try{
                        JsonConvert.DeserializeObject<Category>(Request.Body);
                    }
                    catch(Exception e)
                    {
                        Console.WriteLine("ParseError!" + e.ToString());
                        messages.Add("illegal body");
                    }
                }
            }

            // Concatenating all the messages for the client.
            Response.Status = String.Join(", ", messages);

            Console.WriteLine("Status: " + Response.Status);

            if (Response.Status.Length > 0)
            return false;
            else {
                Response = new RdjtpResponse(RdjtpStatus.Ok);
                return true;
            }
        }

        private bool HeadersValid()
        {
            // TODO: apparently, when "echo" requested, no need to check for path

            bool mandatoryHeadersPresent =
                Request.Method == null ||
                Request.Path == null ||
                Request.Date == 0 ? false : true;

            bool mandatoryHeadersCorrect = _acceptedMethods.Contains(Request.Method) ? true : false;

            bool bodyPresentIfNeeded =
                (Request.Method == "create" ||
                Request.Method == "update" ||
                Request.Method == "echo") &&
                Request.Body == null ? false : true;

            return mandatoryHeadersPresent && mandatoryHeadersCorrect && bodyPresentIfNeeded;
        }
    }
}
